#include "httpinstanceimpl.h"

CHttpInstanceImpl::CHttpInstanceImpl()
{
	m_httpcontent_length	= 0;
	m_hstid					= HTTP_IMPL_START;
}

CHttpInstanceImpl::~CHttpInstanceImpl(void)
{
	logi("CHttptImpl::~CHttptImpl");
}

//std_method_impl CHttpInstanceImpl::init_class(IBase* pSocket, IBase* pIOper, IBase* pIDns)

std_method_impl CHttpInstanceImpl::init_class(AsynFrameConstPtr AsynFrame, NetConstPtr Net)
{

	HRESULT		hr = S_OK;

	BasePtr pBase;
	hr = this->QueryInterface(IID_IBase, (void**)&pBase);
	rc_assert(hr == S_OK, E_FAIL)

	hr = AsynFrame->CreateIo(io_tcp_socket, (IBase**)&m_pISocket.m_p);
	rc_assert(hr == S_OK, E_FAIL)

	hr = AsynFrame->CreateIo(io_operation, (IBase**)&m_pIOper.m_p);
	rc_assert(hr == S_OK, E_FAIL)

	hr = m_pIOper->BindEvent(pBase);
	rc_assert(hr == S_OK, E_FAIL)

	hr = Net->CreateProtocol(Protocol_dns, (IBase**)&m_pIDns);
	rc_assert(hr == S_OK, E_FAIL)

	http_init_analyze(http_response);

	BUFFER_SIZE BufLen = 16 * 1024;

	m_pIOper->Alloc(BufLen);

	m_pISocket->OpenIo();

	m_pISocket->SetOption(SOL_SENDLEN, 16384);

	m_pISocket->SetOption(SOL_RECVLEN, 16384);

	m_pISocket->SetOption(SOL_SENDTM, 5);

	m_pISocket->SetOption(SOL_RECVTM, 5);

	m_pISocket->SetOption(SOL_CONTM, 5);


	return S_OK;
}

std_method_impl CHttpInstanceImpl::BindEvent(IBase* pBase)
{
	rc_assert(m_pHandle != INULL, E_FAIL)
	m_pHandle.dispose();
	return pBase->QueryInterface(IID_IHttpInstanceProc, (void**)&m_pHandle);
}
std_method_impl CHttpInstanceImpl::UnBindEvent()
{
	m_pHandle.dispose();
	return S_OK;
}
std_method_impl CHttpInstanceImpl::SetCookies(http_header_data *data)
{
	return S_OK;
}
std_method_impl CHttpInstanceImpl::Open(http_addr_s url, http_addr_s scheme, http_port uport)
{
	OnBuildHttp(url, scheme,uport);
	return OnConnect(url, uport);
}
std_method_type_impl(http_header) CHttpInstanceImpl::GetHttpHead()
{
	return m_szhttpHead;
}
std_method_impl CHttpInstanceImpl::ReSet()
{
	Cancel();
	return S_OK;
}
std_method_impl CHttpInstanceImpl::Cancel()
{
	httpEventComplate(m_pISocket, m_pIOper);
	m_hstid = HTTP_IMPL_START;
	http_init_analyze(http_response);

	HRESULT		hr = S_OK;

	hr = m_pISocket->CloseIo(CLOSE_BOTH_IO);
	rc_assert(hr == S_OK, E_FAIL)

	hr = m_pISocket->CloseSock();
	
	m_pISocket.dispose();

	m_pIOper->UnBindEvent();

	m_pIOper.dispose();

	m_pIDns.dispose();

	return S_OK;
}
std_method_type_impl(int) CHttpInstanceImpl::IsComplete()
{
	return m_parser->content_length == 0;
}
std_method_impl CHttpInstanceImpl::OnComplete(IBase *pOperation, event_id event, ULONG error_code)
{
	HRESULT		hr = S_OK;

	//if (lErrorCode){

	//	char szlog[128] = { 0x00 };
	//	sprintf(szlog, "AT %s: CHttpImpl OnOperationComplete error : %lu \n", AT, lErrorCode);
	//	debug_view(szlog);

	//	if (OP_EOF == lErrorCode) {
	//		m_hstid = HTTP_IMPL_END;
	//	} else {
	//		m_hstid = Id_Faild(m_pIOper->GetId());
	//	}

	//	Notify(m_hstid);

	//} else {
	//	//hr = httpEventProc(m_pIOper->GetId(), pOperation);

	//	m_hstid = Notify(m_pIOper->GetId());

	//	//hr = httpEvent(m_hstid, m_pIAsyncTcpSocket, pOperation);

	//	return hr;
	//}
	return S_OK;
}

std_method_impl CHttpInstanceImpl::OnGetHost(int error, LPCSTR hostname, LPCSTR host)
{	
	if (m_hstid < HTTP_IMPL_CONNECTING && DNS_PROC_RES_NOERROR == error) {
		httpConnect(m_pIOper.m_p, host, m_uport);
		m_hstid = HTTP_IMPL_CONNECTING;
		return E_FAIL;
	} else {
		 if (DNS_PROC_RES_ERROR == error) {
			logi("http->DNS_PROC_RES_ERROR");
		} else {
			logi("http->DNS_ERROR");
		}
		return E_FAIL;
	}
	return S_OK;
}
ULONG CHttpInstanceImpl::Notify(ULONG ulevent)
{
	rc_assert(m_pHandle != NULL, HTTP_IMPL_UNKNOWN)
	return m_pHandle->Event(ulevent);
}
ULONG CHttpInstanceImpl::Id_Suc(ULONG ulid) {

	ulid++;
	ulid++;
	return ulid;
}
std_method_impl CHttpInstanceImpl::httpEventProc(ULONG ulevent, IOperation *pOperation)
{
	HRESULT hr = S_OK;

	switch (ulevent)
	{
	case HTTP_IMPL_CONNECTING:
		httpConnected(pOperation);
		break;
	case HTTP_IMPL_SEND_HEAD:
		httpSendHeaded(pOperation);
		break;
	case HTTP_IMPL_SEND_BODY:
		httpSendBodyed(pOperation);
		break;
	case HTTP_IMPL_RECV_HEAD:
		httpRecvHeaded(pOperation);
		break;
	case HTTP_IMPL_RECV_BODY:
		httpRecvBodyed(pOperation);
		break;
	default:
		break;
	}

	return hr;
}
std_method_impl CHttpInstanceImpl::httpConnected(IOperation *pOperation)
{
	HRESULT hr = S_OK;

	pOperation->SetId(HTTP_IMPL_CONNECTED);

	return hr;
}
std_method_impl CHttpInstanceImpl::httpSendHeaded(IOperation *pOperation)
{
	HRESULT hr = S_OK;

	pOperation->SetId(HTTP_IMPL_SEND_HEADED);

	return hr;
}
std_method_impl CHttpInstanceImpl::httpSendBodyed(IOperation *pOperation)
{
	HRESULT hr = S_OK;

	pOperation->SetId(HTTP_IMPL_SEND_BODYED);

	return hr;
}
std_method_impl CHttpInstanceImpl::httpRecvHeaded(IOperation *pOperation)
{
	HRESULT hr = S_OK;

	//pOperation->SetId(HTTP_IMPL_RECV_HEADED);

	//ERROR_CODE errcode = 0;
	//ULONG pTransferedBytes = 0;

	//pOperation->GetResult(&errcode, &pTransferedBytes);

	//ULONG pIoStartPos = 0;
	//ULONG pIoExpectBytes = 0;
	//pOperation->GetIoParam(&pIoStartPos, &pIoExpectBytes);
	//
	//BUFFER_PTR ptr = NULL;
	//pOperation->GetIo(&ptr, &pIoStartPos);
	//rc_assert(ptr != NULL,E_FAIL)

	//m_parser->p = ptr;
	//http_analyze((char*)ptr, pTransferedBytes);
	
	return hr;
}
std_method_impl CHttpInstanceImpl::httpRecvBodyed(IOperation *pOperation)
{
	HRESULT hr = S_OK;

	//pOperation->SetId(HTTP_IMPL_RECV_BODYED);
	//ERROR_CODE errcode = 0;
	//ULONG pTransferedBytes = 0;
	//pOperation->GetResult(&errcode, &pTransferedBytes);

	//ULONG pIoStartPos = 0;
	//ULONG pIoExpectBytes = 0;
	//pOperation->GetIoParam(&pIoStartPos, &pIoExpectBytes);


	//BUFFER_PTR ptr = NULL;
	//pOperation->GetIo(&ptr, &pIoStartPos);
	//rc_assert(ptr != NULL, E_FAIL)

	//m_parser->p = ptr;
	//http_analyze((char*)ptr, pTransferedBytes);

	return hr;
}

std_method_impl CHttpInstanceImpl::httpEvent(ULONG ulevent, ITcpSocket* pSocket, IOperation *pOperation)
{
	HRESULT hr = E_FAIL;

	switch (ulevent)
	{
	case HTTP_IMPL_SEND_HEAD:
		hr = httpSendHead(pSocket, pOperation);
		break;
	case HTTP_IMPL_SEND_BODY:
		hr = httpSendBody(pSocket, pOperation);
		break;
	case HTTP_IMPL_RECV_HEAD:
		hr = httpRecvHead(pSocket, pOperation);
		break;
	case HTTP_IMPL_RECV_BODY:
		hr = httpRecvBody(pSocket, pOperation);
		break;
	case HTTP_IMPL_END:
		hr = S_OK;
		break;
	default:
		break;
	}
	return hr;
}
std_method_impl CHttpInstanceImpl::httpEventComplate(ITcpSocket* pSocket, IOperation *pOperation)
{
	HRESULT hr = S_OK;

	return hr;
}
ULONG CHttpInstanceImpl::Id_Faild(ULONG ulid) {

	ulid++;
	return ulid;
}
std_method_impl CHttpInstanceImpl::httpConnect(IOperation *pOperation, NET_ADDR addr, NET_PORT uport)
{
	logi("CHttpClientImpl::httpConnect %s", addr);
	pOperation->SetId(HTTP_IMPL_CONNECTING);
	return m_pISocket->ConnectIo(addr,uport,pOperation, HTTP_IMPL_CONNECTING);
}
std_method_impl CHttpInstanceImpl::httpSendHead(ITcpSocket* pSocket, IOperation *pOperation)
{
	const char* p = m_http_resheader.build_res();
	size_t ulen = m_http_resheader.build_res_len();
	return httpSend(HTTP_IMPL_SEND_HEAD, pSocket, pOperation);
}
std_method_impl CHttpInstanceImpl::httpSendBody(ITcpSocket* pSocket, IOperation *pOperation)
{
	return httpSend(HTTP_IMPL_SEND_BODY, pSocket, pOperation);
}
std_method_impl CHttpInstanceImpl::httpRecvHead(ITcpSocket* pSocket, IOperation *pOperation)
{
	return httpRecv(HTTP_IMPL_RECV_HEAD, pSocket, pOperation);
}
std_method_impl CHttpInstanceImpl::httpRecvBody(ITcpSocket* pSocket, IOperation *pOperation)
{
	return httpRecv(HTTP_IMPL_RECV_BODY, pSocket, pOperation);
}

std_method_impl CHttpInstanceImpl::httpSend(ULONG uid, ITcpSocket* pSocket, IOperation *pOperation)
{
	pOperation->SetId(uid);
	return pSocket->WriteIo(pOperation, uid);
}
std_method_impl CHttpInstanceImpl::httpRecv(ULONG uid, ITcpSocket* pSocket, IOperation *pOperation)
{
	pOperation->SetId(uid);
	return pSocket->ReadIo(pOperation, uid);
}
void CHttpInstanceImpl::on_http_message_begin()
{
	c_assert(m_parser)
}
void CHttpInstanceImpl::on_http_header_complete()
{
	c_assert(m_parser)
	m_httpcontent_length = m_parser->content_length;
	m_szhttpHead = new char[m_parser->nread + 1]();
	memcpy(m_szhttpHead, m_parser->p, m_parser->nread);
}
void CHttpInstanceImpl::on_http_body(const char* at, size_t length)
{		
	c_assert(m_parser)
	//m_Notify->RecvBody((void*)at, length, 1);
}
void CHttpInstanceImpl::on_http_message_complete()
{
	c_assert(m_parser)
}

std_method_impl CHttpInstanceImpl::OnConnect(NET_ADDR url, NET_PORT uport)
{
	HRESULT		hr = S_OK;

	m_uport = uport;

	if (_is_ip(url)) {
		hr = httpConnect(m_pIOper.m_p, url, m_uport);
	}
	else {
		//hr = m_pIDns->GetURLtoHost(url, "", "http", this, NULL, NULL, 1);
	}
	return hr;
}
std_method_impl CHttpInstanceImpl::OnBuildHttp(http_addr_s url, http_addr_s scheme, NET_PORT uport)
{
	m_http_resheader.set_method(scheme);
	
	char szPort[32] = { 0x00 };
	snprintf(szPort, sizeof(szPort), ":%u", uport);
	string strurl(url);
	strurl.append(szPort);
	m_http_resheader.set_host(strurl.c_str());
	m_http_resheader.set_accept("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
	m_http_resheader.set_accept_language("zh-CN");
	m_http_resheader.set_cache_control("no-cache");
	m_http_resheader.set_accept_encoding("gzip, deflate, br");
	m_http_resheader.set_use_agent("Mozilla/5.0 (Windows NT 10.0; Win64; x64; ServiceUI 13.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/17.17134");
	m_http_resheader.build_res_http();


	return S_OK;
}





